const PENDING = 'pending', FULFILLED = 'fulfilled', REJECTED = 'rejected'
class YGPromise {
    constructor(executor) {
        executor(this.resolve, this.reject)
    }
    status = PENDING
    value = null
    reason = null
    onFulfilledCbs = []
    onRejectedCbs = []
    resolve = value => {
        if (this.status === PENDING) {
            this.status = FULFILLED
            this.value = value
            while (this.onFulfilledCbs.length) {
                this.onFulfilledCbs.shift()(this.value)
            }
        }
    }
    reject = reason => {
        if (this.status === PENDING) {
            this.status = REJECTED
            this.reason = reason
            while (this.onRejectedCbs.length) {
                this.onRejectedCbs.shift()(this.reason)
            }
        }
    }
    then = (onFulfilled, onRejected) => {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
        onRejected = typeof onRejected === 'function' ? onRejected : reason => reason
        const p = new YGPromise ((resolve, reject) => {
            const fulfilledMicrotask = () => {
                try {
                    queueMicrotask(() => {
                        const x = onFulfilled(this.value)
                        resolvePromise(x, p, resolve, reject)
                    })
                } catch (error) {
                    reject(error)
                }
            }
            const rejectedMicrotask = () => {
                try {
                    queueMicrotask(() => {
                        const x = onRejected(this.reason)
                        resolvePromise(x, p, resolve, reject)
                    })
                } catch (error) {
                    reject(error)
                }
            }
            if (this.status === FULFILLED) {
                fulfilledMicrotask()
            } else if (this.status === REJECTED) {
                rejectedMicrotask()
            } else {
                this.onFulfilledCbs.push(fulfilledMicrotask)
                this.onRejectedCbs.push(rejectedMicrotask)
            }
        })
        return p
    }
    static resolve = (param) => {
        if (param instanceof YGPromise) {
            return param
        } else {
            return new YGPromise ((resolve, reject) => {
                resolve(param)
            })
        }
    }
    static reject = (param) => {
        return new YGPromise ((resolve, reject) => {
            reject(param)
        })
    }
}
function resolvePromise(x, p, resolve, reject) {
    if (x instanceof YGPromise) {
        if (x === p) {
            throw new Error('promise cycle error')
        } else {
            x.then(resolve, reject)
        }
    } else {
        resolve(x)
    }
}

const p = new YGPromise((resolve, reject) => {
    // resolve('resolve success')
    // reject('rejecte err')
    setTimeout(() => {
        resolve('resolve success')
    }, 2000);
})
p.then(
    value => {
        console.log(value)
        return new YGPromise((resolve, reject) => {
            resolve('other promise resolve success')
        })
    },
    reason => {
        console.log(reason)
    }
).then( 
    value => {
        console.log(value)
    },
    reason => {
        console.log(reason)
    }
)

YGPromise.resolve('1').then(
    value => {
        return 123
    }
).then(value => console.log(value))
YGPromise.reject('2 err').then(
    value => console.log(value),
    reason => console.log(reason)
)